from abc import ABC, abstractmethod
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING
import random
from datetime import datetime, timedelta

if TYPE_CHECKING:
    from items.base_item import Item
class Champion(ABC):
    def __init__(self, name: str, health: int, attack: int, defense: int, 
                 speed: int, mana: int = 100):
        self._name = name
        self._max_health = health
        self._current_health = health
        self._base_attack = attack
        self._base_defense = defense
        self._base_speed = speed
        self._max_mana = mana
        self._current_mana = mana
        self._is_alive = True
        self._is_stunned = False
        self._is_silenced = False
        self._buffs = []
        self._debuffs = []
        
        self._equipped_items = []
        
        self._ability_cooldowns = {}
        
        self._level = 1
        self._experience = 0
        self._experience_to_next_level = 100
    
    @property
    def name(self) -> str:
        return self._name
    
    @property
    def health(self) -> int:
        return self._current_health
    
    @property
    def max_health(self) -> int:
        return self._max_health
    
    @property
    def attack(self) -> int:
        total_attack = self._base_attack
        for item in self._equipped_items:
            total_attack += item.attack_bonus
        return total_attack
    
    @property
    def defense(self) -> int:
        total_defense = self._base_defense
        for item in self._equipped_items:
            total_defense += item.defense_bonus
        return total_defense
    
    @property
    def speed(self) -> int:
        total_speed = self._base_speed
        for item in self._equipped_items:
            total_speed += item.speed_bonus
        return total_speed
    
    @property
    def mana(self) -> int:
        return self._current_mana
    
    @property
    def max_mana(self) -> int:
        return self._max_mana
    
    @property
    def is_alive(self) -> bool:
        return self._is_alive
    
    @property
    def level(self) -> int:
        return self._level
    
    @abstractmethod
    def get_abilities(self) -> List[str]:
        pass
    
    @abstractmethod
    def use_ability(self, ability_name: str, target: Optional['Champion'] = None) -> Dict:
        pass
    
    @abstractmethod
    def get_champion_type(self) -> str:
        pass
    
    def take_damage(self, damage: int, damage_type: str = "physical") -> int:
        if not self._is_alive:
            return 0
        
        if damage_type == "physical":
            actual_damage = max(1, damage - self.defense)
        elif damage_type == "magical":
            actual_damage = max(1, damage - (self.defense // 2))
        else:  
            actual_damage = damage
        
        self._current_health = max(0, self._current_health - actual_damage)
        
        if self._current_health <= 0:
            self._is_alive = False
            self._current_health = 0
        
        return actual_damage
    
    def heal(self, amount: int) -> int:
        if not self._is_alive:
            return 0
        
        old_health = self._current_health
        self._current_health = min(self._max_health, self._current_health + amount)
        return self._current_health - old_health
    
    def restore_mana(self, amount: int) -> int:
        old_mana = self._current_mana
        self._current_mana = min(self._max_mana, self._current_mana + amount)
        return self._current_mana - old_mana
    
    def consume_mana(self, amount: int) -> bool:
        if self._current_mana >= amount:
            self._current_mana -= amount
            return True
        return False
    
    def attack_target(self, target: 'Champion') -> Dict:
        if not self._is_alive or not target.is_alive:
            return {"success": False, "message": "Cannot attack - champion or target is dead"}
        
        if self._is_stunned:
            return {"success": False, "message": f"{self.name} is stunned and cannot attack"}
        
        base_damage = self.attack
        damage_variance = random.randint(-5, 5)  
        total_damage = max(1, base_damage + damage_variance)
        
        actual_damage = target.take_damage(total_damage, "physical")
        
        return {
            "success": True,
            "damage": actual_damage,
            "message": f"{self.name} attacks {target.name} for {actual_damage} damage!"
        }
    
    def equip_item(self, item: 'Item') -> bool:
        if len(self._equipped_items) >= 6:  
            return False
        
        self._equipped_items.append(item)
        return True
    
    def unequip_item(self, item: 'Item') -> bool:
        if item in self._equipped_items:
            self._equipped_items.remove(item)
            return True
        return False
    
    def gain_experience(self, amount: int) -> bool:
        self._experience += amount
        leveled_up = False
        
        while self._experience >= self._experience_to_next_level:
            self._experience -= self._experience_to_next_level
            self._level += 1
            leveled_up = True
            
            self._max_health += 10
            self._current_health = self._max_health  
            self._base_attack += 2
            self._base_defense += 1
            self._base_speed += 1
            self._max_mana += 5
            self._current_mana = self._max_mana
            
            self._experience_to_next_level = int(self._experience_to_next_level * 1.2)
        
        return leveled_up
    
    def reset_for_battle(self):
        self._current_health = self._max_health
        self._current_mana = self._max_mana
        self._is_alive = True
        self._is_stunned = False
        self._is_silenced = False
        self._buffs.clear()
        self._debuffs.clear()
        self._ability_cooldowns.clear()
    
    def get_status(self) -> Dict:
        return {
            "name": self.name,
            "level": self.level,
            "health": f"{self.health}/{self.max_health}",
            "mana": f"{self.mana}/{self.max_mana}",
            "attack": self.attack,
            "defense": self.defense,
            "speed": self.speed,
            "is_alive": self.is_alive,
            "is_stunned": self._is_stunned,
            "is_silenced": self._is_silenced,
            "equipped_items": len(self._equipped_items)
        }
    
    def __str__(self) -> str:
        return f"{self.name} (Level {self.level}) - {self.health}/{self.max_health} HP, {self.mana}/{self.max_mana} MP"
    
    def __repr__(self) -> str:
        return f"{self.__class__.__name__}(name='{self.name}', level={self.level})"

